using System;
using System.Collections.Generic;
using System.Text;

namespace Taumuon.Jabuka.Physics.Test
{
    /// <summary>
    /// Specifies a factory to separate the out the logic
    ///  for how the mocks in the ICloneable.Clone() method
    ///  are returned.
    /// </summary>
    public interface IMockClonesFactory<T> where T : class
    {
        /// <summary>
        /// Retrieves the next clone.
        /// </summary>
        /// <returns>An object of type T.</returns>
        T GetNextClone();
    }

    /// <summary>
    /// Returns a set of clones that the user specifies.
    /// </summary>
    public class MockFactoryClonesSpecified<T>
        : IMockClonesFactory<T>
        where T : class
    {
        #region IMockClonesFactory Members

        /// <summary>
        /// Implementation of IMockClonesFactory
        /// </summary>
        /// <returns></returns>
        public T GetNextClone()
        {
            return this.clone;
        }

        #endregion

        /// <summary>
        /// Sets the mock clone to return
        ///  when Clone is called.
        /// </summary>
        internal T MockClone
        {
            set
            {
                this.clone = value;
            }
        }

        #region Private Member Variables

        private T clone = null;

        #endregion Private Member Variables
    }

    /// <summary>
    /// This factory is used for testing the iteration to find
    ///  the time of collision.
    /// </summary>
    public class MockSphereFactoryIteration
        : IMockClonesFactory<MockSphere>
    {
        /// <summary>
        /// Returns mocks for iteration tests.
        /// </summary>
        public MockSphereFactoryIteration(IEulerRigidBody mockEulerRigidBody,
            double timeOfCollision)
        {
            this.mockEulerRigidBody = mockEulerRigidBody;
            this.timeOfCollision = timeOfCollision;
        }

        #region IMockClonesFactory<MockSphere> Members

        /// <summary>
        /// IMockClonesFactory implementation
        /// </summary>
        public MockSphere GetNextClone()
        {
            MockSphereIterations mockSphereIterations =
                new MockSphereIterations((IEulerRigidBody)this.mockEulerRigidBody.Clone(), timeOfCollision);
            return mockSphereIterations;
        }

        #endregion

        #region Private Member Variables

        private IEulerRigidBody mockEulerRigidBody;
        private double timeOfCollision;

        #endregion Private Member Variables
    }

    /// <summary>
    /// Clones factory used for iteration tests.
    /// </summary>
    public class MockEulerRigidBodyFactoryIteration
        : IMockClonesFactory<MockEulerRigidBody>
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public MockEulerRigidBodyFactoryIteration(MockEulerRigidBody originalMockEulerRigidBody)
        {
            this.originalMockEulerRigidBody = originalMockEulerRigidBody;
        }

        #region IMockClonesFactory<MockEulerRigidBody> Members

        /// <summary>
        /// Implementation of IMockClonesFactory
        /// </summary>
        public MockEulerRigidBody GetNextClone()
        {
            MockEulerRigidBody mockEulerRigidBody
                = new MockEulerRigidBody(
                new Vector(originalMockEulerRigidBody.Location.X,
                originalMockEulerRigidBody.Location.Y,
                originalMockEulerRigidBody.Location.Z),
                new Vector(originalMockEulerRigidBody.Velocity.X,
                originalMockEulerRigidBody.Velocity.Y,
                originalMockEulerRigidBody.Velocity.Z),
                new Vector(originalMockEulerRigidBody.Acceleration.X,
                originalMockEulerRigidBody.Acceleration.Y,
                originalMockEulerRigidBody.Acceleration.Z),
                originalMockEulerRigidBody.Mass);
            mockEulerRigidBody.CloneFactory = originalMockEulerRigidBody.CloneFactory;
            return mockEulerRigidBody;
        }

        #endregion

        private MockEulerRigidBody originalMockEulerRigidBody = null;
    }
}
